<?php

/*
 * Obj
 * Author: LiuYuanjun
 * E-Mail/MSN: lane@live.cn
 * QQ: 6879391
 */

abstract class Obj {

    public $dbData = array();
    public $primary = null;
    public $db = null;
    protected $_DirtyFields = array();
// >= PHP 5.3 Start
    protected static $_instance = array();

    public static function I($primary='') {
        if ($primary) {
            $identify = is_array($primary) ? md5(serialize($config)) : $primary;
            if (!isset(static::$_instance[$identify])) {
                static::$_instance[$identify] = new static($identify);
            }
            return static::$_instance[$primary];
        } else {
            return new static;
        }
    }
// >= PHP 5.3 End

    abstract protected function getTableName();

    abstract protected function getPrimaryField();

    public function __construct($primary='') {
        $this->db = Db::I();
        $primary && $this->_initialize($primary);
    }

    public function __destruct() {
        $this->dbUpdate();
    }

    public function _initialize($primary) {
        $this->primary = $primary;
        if (!$this->getDbData())
            return false;
    }

    protected function isAutoIncrement() {
        return true;
    }

    protected function isSetAble($key) {
        return true;
    }

    protected function isArray($field) {
        return false;
    }

    protected function isCompress($field) {
        return false;
    }

    public function __set($name, $value) {
        if (!$this->isSetAble($name))
            return false;
        if ($this->dbData[$name] !== $value) {
            if ($this->isArray($name) && !is_array($value)) {
                $this->dbData[$name][] = $value;
            } else {
                $this->dbData[$name] = $value;
            }
            $this->_DirtyFields[$name] = true;
        }
    }

    public function __get($name) {
        if ($this->isArray($name))
            $this->dbData[$name] = unserialize($this->dbData[$name]);
        if ($this->isArray($name) && empty($this->dbData[$name])) {
            return $this->dbData[$name] = array();
        } elseif (!isset($this->dbData[$name])) {
            return $this->dbData[$name] = NULL;
        }
        return $this->isArray($name) ? new ArrayObject($this->dbData[$name]) : $this->dbData[$name];
    }

    protected function getPrimaryWhere() {
        $this->getPrimaryField() || throw_exception('NO_PRIMARY');
        is_array($this->primary) !== ($isArray = is_array($this->getPrimaryField())) && throw_exception('WRONG_PRIMARY_TYPE');
        $where = array();
        if ($isArray) {
            $where = array('_logic' => 'AND');
            foreach ($this->getPrimaryField() as $key) {
                $where[] = array($key, 'eq', $this->primary[$key]);
            }
        } else {
            $where = array($this->getPrimaryField(), 'eq', $this->primary);
        }
        return $where;
    }

    public function getDbData($fields='*') {
        if ($this->dbData = $this->db->table($this->getTableName())->field($fields)->where($this->getPrimaryWhere())->find()) {
            $this->_DirtyFields = array();
            return $this->dbData;
        }
        return false;
    }

    public function dbInsert() {
        if (is_array($this->getPrimaryField())) {
            $this->primary = array();
            foreach ($this->getPrimaryField() as $val) {
                $this->dbData[$val] || throw_exception('PRIMARY_IS_NOT_SET');
                $this->primary[$val] = $this->dbData[$val];
            }
        } elseif (!$this->isAutoIncrement()) {
            $this->dbData[$this->getPrimaryField()] || throw_exception('PRIMARY_IS_NOT_SET');
            $this->primary = $this->dbData[$this->getPrimaryField()];
        }
        $dataTmp = array();
        foreach ($this->dbData as $name => $value) {
            $this->isArray($name) && $dataTmp[$name] = serialize($value);
            $this->isCompress($name) && $dataTmp[$name] = gzcompress($value);
        }
        $this->_DirtyFields = array();
        if ($this->db->table($this->getTableName())->insert($dataTmp)) {
            $this->isAutoIncrement() && $this->primary = $this->db->getLastInsID();
            $identify = is_array($this->primary) ? md5(serialize($this->primary)) : md5($this->primary);
            self::$_instance[$identify] = $this;
            return true;
        }
        return false;
    }

    public function dbUpdate() {
        $dataTmp = array();
        foreach (array_keys($this->_DirtyFields) as $name) {
            if ($this->isArray($name)) {
                $dataTmp[$name] = serialize($this->dbData[$name]);
            } elseif ($this->isCompress($name)) {
                $dataTmp[$name] = gzcompress($this->dbData[$name]);
            } else {
                $dataTmp[$name] = $this->dbData[$name];
            }
        }
        if ($dataTmp) {
            if (false === $this->db->table($this->getTableName())->where($this->getPrimaryWhere())->update($dataTmp))
                return false;
            $this->_DirtyFields = array();
        }
        return true;
    }

    public function dbDelete() {
        if (!$this->db->table($this->getTableName())->where($this->getPrimaryWhere())->delete())
            return false;
        $this->_DirtyFields = array();
        return true;
    }

}

?>
